﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
using Autofac;
using ComputerVision.BaseForm;
using ComputerVision.Common;
using ComputerVision.Data;
using ComputerVision.Services;
using DirectShowLib;
using Emgu.CV;

namespace ComputerVision
{
    public partial class frmConfigCamera : frmObject
    {
        #region Camera Capture Variables
        private Capture _capture; //Camera
        private bool _captureInProgress; //Variable to track camera state
        private int CameraDevice = 0; //Variable to track camera device selected
        private VideoDevice[] WebCams; //List containing all the camera available

        #endregion

        private readonly IService<ConfigrationCamera> _configCameraService;
        private string _computerName;

        public frmConfigCamera()
        {
            InitializeComponent();
            _computerName = Environment.MachineName;
            _configCameraService = Program.Container.Resolve<IService<ConfigrationCamera>>();
            var items = _configCameraService.ToList().ToList().Where(p => p.ComputerName.Contains(_computerName)).OrderBy(a => a.Name).ToList();
            var systemCamereas = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

            WebCams = new VideoDevice[systemCamereas.Length];
            for (int i = 0; i < systemCamereas.Length; i++)
            {
                WebCams[i] = new VideoDevice(i, systemCamereas[i].Name, systemCamereas[i].ClassID);
                //fill web cam array
                cmbFirstCamera.Items.Add(WebCams[i]);
                cmbSeconCamera.Items.Add(WebCams[i]);
            }

            SelectCamera(items);
            cmbFirstCamera.Enabled = false;
            cmbSeconCamera.Enabled = false;
        }

        /// <summary>
        /// Thread safe method to display image in a picturebox that is set to automatic sizing
        /// </summary>
        /// <param name="image"></param>
        private delegate void DisplayImageDelegate(Bitmap image);

        private void DisplayImage(Bitmap image)
        {
            if (captureBoxInput.InvokeRequired)
            {
                try
                {
                    var di = new DisplayImageDelegate(DisplayImage);
                    BeginInvoke(di, new object[] { image });
                }
                catch (Exception ex)
                {
                }
            }
            else
            {
                captureBoxInput.Image = image;
            }
        }

        /// <summary>
        /// Sets up the _capture variable with the selected camera index
        /// </summary>
        /// <param name="cameraIdentifier"></param>
        private void SetupCapture(int cameraIdentifier)
        {
            //update the selected device
            CameraDevice = cameraIdentifier;

            //Dispose of Capture if it was created before
            if (_capture != null) _capture.Dispose();
            try
            {
                //    //Set up capture device
                _capture = new Capture(CameraDevice);
                _capture.ImageGrabbed += ProcessFrame;
            }
            catch (Exception excpt)
            {
                MessageBox.Show(excpt.Message);
            }
        }

        /// <summary>
        /// What to do with each frame aquired from the camera
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="arg"></param>
        private void ProcessFrame(object sender, EventArgs arg)
        {
            var frame = _capture.RetrieveBgrFrame();
            //because we are using an autosize picturebox we need to do a thread safe update
            DisplayImage(frame.ToBitmap());
        }

        private void cmbFirstCamera_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            if (_capture != null)
            {
                if (_captureInProgress)
                {
                    _capture.Pause(); //Pause the capture
                    _captureInProgress = false; //Flag the state of the camera
                }
                else
                {
                    //Check to see if the selected device has changed
                    if (cmbFirstCamera.SelectedIndex != CameraDevice)
                    {
                        SetupCapture(cmbFirstCamera.SelectedIndex); //Setup capture with the new device
                    }

                    _capture.Start(); //Start the capture
                    _captureInProgress = true; //Flag the state of the camera
                }
            }
            else
            {
                //set up capture with selected device
                SetupCapture(cmbFirstCamera.SelectedIndex);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        #region Validation

        protected bool Validator()
        {
            if (cmbFirstCamera.SelectedItem == null)
            {
                AlertList.Error("Bạn phải chọn Camera trước.");
                return false;
            }

            if (cmbSeconCamera.SelectedItem == null)
            {
                AlertList.Error("Bạn phải chọn Camera sau.");
                return false;
            }

            return true;
        }

        #endregion

        protected void Insert()
        {
            try
            {
                var cameraFirst = cmbFirstCamera.SelectedItem as VideoDevice;
                var cameraSecond = cmbSeconCamera.SelectedItem as VideoDevice;

                var modelFirst = new ConfigrationCamera
                {
                    Id = Guid.NewGuid(),
                    ComputerName = _computerName,
                    Name = Constants.CameraPosition.First,
                    DeviceId = cameraFirst.DeviceId,
                    DeviceName = cameraFirst.DeviceName,
                    Identifier = cameraFirst.Identifier,
                    Created = DateTime.Now,
                    CreatedBy = Constants.CurrentUser,
                    Modified = DateTime.Now,
                    ModifiedBy = Constants.CurrentUser
                };
                _configCameraService.Create(modelFirst);

                var modelSecond = new ConfigrationCamera
                {
                    Id = Guid.NewGuid(),
                    ComputerName = _computerName,
                    Name = Constants.CameraPosition.Second,
                    DeviceId = cameraSecond.DeviceId,
                    DeviceName = cameraSecond.DeviceName,
                    Identifier = cameraSecond.Identifier,
                    Created = DateTime.Now,
                    CreatedBy = Constants.CurrentUser,
                    Modified = DateTime.Now,
                    ModifiedBy = Constants.CurrentUser
                };
                _configCameraService.Create(modelSecond);

                AlertList.Information("Thiết lập camera thành công.");
                this.Close();
            }
            catch (Exception ex)
            {
                AlertList.Error("Lỗi phát sinh khi tạo mới dữ liệu.");
            }
        }

        #region Edit

        protected void Edit(List<ConfigrationCamera> items)
        {
            try
            {
                var cameraFirst = cmbFirstCamera.SelectedItem as VideoDevice;
                var cameraSecond = cmbSeconCamera.SelectedItem as VideoDevice;
                var itemFirst = _configCameraService.Detail(items[0].Id);
                if (itemFirst != null)
                {
                    itemFirst.ComputerName = _computerName;
                    itemFirst.Name = Constants.CameraPosition.First;
                    itemFirst.DeviceId = cameraFirst.DeviceId;
                    itemFirst.DeviceName = cameraFirst.DeviceName;
                    itemFirst.Identifier = cameraFirst.Identifier;
                    itemFirst.Modified = DateTime.Now;
                    itemFirst.ModifiedBy = Constants.CurrentUser;
                    _configCameraService.Update(itemFirst);
                }

                var itemSecond = _configCameraService.Detail(items[1].Id);
                if (itemSecond != null)
                {
                    itemSecond.ComputerName = _computerName;
                    itemSecond.Name = Constants.CameraPosition.Second;
                    itemSecond.DeviceId = cameraSecond.DeviceId;
                    itemSecond.DeviceName = cameraSecond.DeviceName;
                    itemSecond.Identifier = cameraSecond.Identifier;
                    itemSecond.Modified = DateTime.Now;
                    itemSecond.ModifiedBy = Constants.CurrentUser;
                    _configCameraService.Update(itemSecond);
                }

                AlertList.Information("Thiết lập camera thành công.");
                this.Close();

            }
            catch (Exception)
            {
                AlertList.Error("Lỗi phát sinh khi thiết lập dữ liệu.");
            }

        }

        #endregion

        private void DeleteData(List<ConfigrationCamera> items)
        {
            try
            {
                foreach (ConfigrationCamera item in items)
                {
                    var it = _configCameraService.Detail(item.Id);
                    _configCameraService.Delete(it);
                }

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        private void SelectCamera(List<ConfigrationCamera> items)
        {
            var item = items.FirstOrDefault(p => p.Name.Contains(Constants.CameraPosition.First));
            if (item != null)
            {
                foreach (VideoDevice videoDevice in cmbFirstCamera.Items)
                {
                    if (videoDevice.DeviceName == item.DeviceName)
                    {
                        cmbFirstCamera.SelectedItem = videoDevice;
                        break;
                    }
                }
            }

            item = items.FirstOrDefault(p => p.Name.Contains(Constants.CameraPosition.Second));
            if (item != null)
            {
                foreach (VideoDevice videoDevice in cmbSeconCamera.Items)
                {
                    if (videoDevice.DeviceName == item.DeviceName)
                    {
                        cmbSeconCamera.SelectedItem = videoDevice;
                        break;
                    }
                }
            }

        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            var items = _configCameraService.ToList().ToList().Where(p => p.ComputerName.Contains(_computerName)).OrderBy(a => a.Name).ToList();

            if (items.Count == 2)
            {
                if (Validator())
                {
                    Edit(items);
                }
            }
            else if (items.Count == 0)
            {
                if (Validator())
                {
                    Insert();
                }
            }
            else
            {
                DeleteData(items);
                if (Validator())
                {
                    Insert();
                }
            }
        }
        
        private void checkFirst_CheckStateChanged(object sender, EventArgs e)
        {
            if (checkFirst.CheckState == CheckState.Checked)
            {
                cmbFirstCamera.Enabled = true;
            }
            else
            {
                cmbFirstCamera.Enabled = false;
            }
        }

        private void checkSecond_CheckStateChanged(object sender, EventArgs e)
        {
            if (checkSecond.CheckState == CheckState.Checked)
            {
                cmbSeconCamera.Enabled = true;
            }
            else
            {
                cmbSeconCamera.Enabled = false;
            }
        }


    }
}